package per.zx;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;

/**
 * @author zhengxin
 * @date 2021/7/6 22:23
 * @description
 */
public class FIFOMutex {

    private final AtomicBoolean locked = new AtomicBoolean(false);
    private final Queue<Thread> waiters = new ConcurrentLinkedDeque<>();

    public void lock() {
        boolean wasInterrupted = false;
        Thread current = Thread.currentThread();
        waiters.add(current);

        // 只有队首的元素可以获得锁
        // 1.判断是不是当前线程，不是就进入while循环
        // 2.如果是当前线程，前一个条件就位false，后一个条件就是将locked从false改为true，如果成功就说明获取锁，取反，不进入while
        while (waiters.peek() != current || !locked.compareAndSet(false, true)) {
            LockSupport.park(this);
            // 如果 park 方法是因为被中断而返回，则忽略中断，并且重置中断标志，做个标记
            if (Thread.interrupted()) // 会将打断标记置为 true
                wasInterrupted = true;  // 做个标记
        }
        waiters.remove(); // 移除当前线程
        if (wasInterrupted)
            // 如果其他线程中断该线程，恢复中断信号
            current.interrupt();

    }

    public void unlock() {
        locked.set(false);
        LockSupport.unpark(waiters.peek()); // 因为获得锁的线程已经被移除 ，所以现在唤醒的是第一个且在阻塞的线程
    }

    public static void main(String[] args) {

    }
}
